class JSInstanceMethod:
  """
  This object helps us pass around data structures that will create
  Javascript Instance Methods.
  """
  # This template lets us define defaults for particular methods:
  # -Is this method called async by default?
  # -Do we cache/check cache for this method?
  # -Do we set the cache to whatever was passed in? (Python Properties!)
  ROPC_string = """%(ObjectName)s.prototype.%(MethodName)s = function(args,options) {
    // This might be a bad idea - cause we *always* have "MethodArgs" then.
    if(!args) { var args = {} }
    var default_options = {"sync":%(sync)s,
                           "cache":%(cache)s,
                           "skipcache":%(skipcache)s,
                           "isproperty":%(isproperty)s,
                           }
    // If a function is passed in as "options", make it the callback.
    if(typeof options == "function") {
      var options = {"cb":options}
    }
    if(typeof options != "object") {
      var options = default_options;
    }
    else {
      options = _PTJS_update(default_options,options)
    }
    // Optional, additional code.
    %(MethodGuts)s   
    /////////////////////////////
    // We only cache if there were no arguments - unless this is a Python property
    if(options['isproperty'] && !_PTJS_isEmpty(args)) {
      this.__dict__['%(MethodName)s'] = args;
    }
    if(!options['skipcache']&&this.__dict__['%(MethodName)s']&&_PTJS_isEmpty(args)) {
      return this.__dict__['%(MethodName)s'];
    }
    var results = this.ROPC("%(MethodName)s",args,options);
    if(options['cache'] && results != null && _PTJS_isEmpty(args)) {
      this.__dict__['%(MethodName)s'] = results;
    }
    return results;
  }
  """

  def __init__(self,MethodName,MethodGuts="",sync=False,cache=False,
                skipcache=True,isproperty=False):
    self.MethodName = MethodName
    self.MethodGuts = MethodGuts
    self.sync = sync
    self.cache = cache
    self.skipcache = skipcache
    self.isproperty = isproperty
    
  @classmethod
  def fromProperty(cls,MethodName,MethodGuts="",sync=True,
                    cache=False,skipcache=False,isproperty=True):
    return JSInstanceMethod(MethodName,MethodGuts,sync,cache,
                            skipcache,isproperty)
  def buildMethod(self,ObjectName):
    return self.ROPC_string % { "ObjectName":ObjectName,
                                "MethodName":self.MethodName,
                                "MethodGuts":self.MethodGuts,
                                "sync":self.sync,
                                "cache":self.cache,
                                "skipcache":self.skipcache,
                                "isproperty":self.isproperty}
class JSClassMethod:
  """
  This object helps us pass around data structures that will create
  Javascript Class Methods.
  """
  RPC_string = """%(ObjectName)s.%(MethodName)s = function(args,options) {
    var default_options = {"sync":%(sync)s,
                           }
    // If a function is passed in as "options", make it the callback.
    if(typeof options == "function") {
      var options = {"cb":options};
    }
    if(typeof options != "object") {
      var options = default_options;
    }
    else {
      options = _PTJS_update(default_options,options)
    }
    return this.RPC("%(MethodName)s",args,options);
  }
  """

  def __init__(self,MethodName,sync):
    self.MethodName = MethodName
    self.sync = sync
    
  def buildMethod(self,ObjectName):
    return self.RPC_string % {"ObjectName":ObjectName,
                              "MethodName":self.MethodName,
                              "sync":self.sync,
                              }


JS_OBJECT = """var %(ObjectName)s = PythonObject.extend({
  _PTJS_ObjectName: "%(ObjectName)s",
  _PTJS_addToCache: %(addToCache)s,
  %(variables)s
})
// Reserved for *special* class methods which have internal code, unlike the
// ones below.
%(classmethods)s
"""


# Should this be here? Maybe .set only belongs to sqlobject?
FUNC_internal = """
                function(arg,options) {
                  if(arg && typeof arg != "undefined" && arg != null) {
                    this.set({'%(name)s':arg},options);
                  }
                  return this.__dict__['%(name)s']
                }"""
